﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProgNetComponents.ExtenderProviders;
using ProgNetDxComponents.ExtenderProviders.Settings;
using DevExpress.XtraEditors;
using System.Windows.Forms;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraBars;
using DevExpress.XtraGrid.Views.Grid;
using System.ComponentModel;
using ProgNetDxComponents.Design;
using System.Data;
using ProgNetComponents;
using ProgNetComponents.Design.Editors;
using System.Drawing.Design;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid;

namespace ProgNetDxComponents.ExtenderProviders
{
    [
        Designer(typeof(DxGridColumnExtenderDesigner))
    ]
    public class ModeProvider : BaseExtenderProvider<ModeSettings>
    {
        public ModeProvider(IContainer c = null) : base(c) { DefaultReadOnlyModes = FormMode.Read | FormMode.View; }
        public ModeProvider() { DefaultReadOnlyModes = FormMode.Read | FormMode.View; }
        private List<GridView> _Views = new List<GridView>();
        private List<GridControl> _Grids = new List<GridControl>();
        public event EventHandler<ChangingEventArgs> CurrentModeChanging;
        public event EventHandler CurrentModeChanged;

        private FormMode _CurrentMode;

        public FormMode CurrentMode
        {
            get { return _CurrentMode; }
            set
            {
                if (_CurrentMode != value)
                {
                    bool allow = true;
                    if (CurrentModeChanging != null)
                    {
                        ChangingEventArgs e = new ChangingEventArgs(_CurrentMode, value);
                        CurrentModeChanging(this, e);
                        allow = !e.Cancel;
                    }
                    if (allow)
                    {
                        _CurrentMode = value;
                        RefreshAllObjects();
                        OnModeChanged();
                        if (CurrentModeChanged != null)
                            CurrentModeChanged(this, EventArgs.Empty);
                    }
                }
            }
        }
        protected void OnModeChanged()
        {
            foreach (GridControl g in _Grids)
            {
                foreach (BaseView v in g.Views)
                {
                   // v.Invalidate();
                    v.RefreshData();
                }
            }
        }

        [Editor(typeof(FlagEnumEditor), typeof(UITypeEditor))]
        public FormMode DefaultReadOnlyModes
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public bool DefaultParentRowAsModeSetterForViews
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public bool DefaultRowAsModeSetterForColumns
        {
            get;
            set;
        }

        protected override void ProcessObject(object sender, ModeSettings settings)
        {
            bool IsReadOnly = (settings.ReadOnlyModes & CurrentMode) != FormMode.None;
            bool IsReq = (settings.RequiredModes & CurrentMode) != FormMode.None;

            if (sender is GridView)
            {
                SettingsCreated(sender, settings);
            }
            else if (sender is GridColumn)
            {
                GridView gv = (sender as GridColumn).View as GridView;
                if (gv != null && !_Views.Contains(gv))
                {
                    _Views.Add(gv);
                    gv.RowCellStyle += new RowCellStyleEventHandler(gv_RowCellStyle);
                    gv.ShowingEditor += new System.ComponentModel.CancelEventHandler(gv_ShowingEditor);
                }
                if (gv.GridControl != null && !_Grids.Contains(gv.GridControl))
                {
                    _Grids.Add(gv.GridControl);
                }
            }
            else if (sender is BaseEdit)
            {
                ModeSettingsEventArgs e = new ModeSettingsEventArgs();
                e.IsReadOnly = IsReadOnly;
                e.IsRequired = IsReq;
                settings.OnCustomGetControlModes(sender, e);
                (sender as BaseEdit).Properties.ReadOnly = e.IsReadOnly;
                if (e.IsReadOnly)
                    (sender as BaseEdit).Properties.Appearance.SetReadOnlyAppearance();
                else if (e.IsRequired)
                    (sender as BaseEdit).Properties.Appearance.SetRequiredAppearance();
                else
                    (sender as BaseEdit).Properties.Appearance.Reset();
            }
            else if (sender is BarItem)
            {
                if (!(sender is BarSubItem))
                {
                    ModeSettingsEventArgs e = new ModeSettingsEventArgs();
                    e.IsReadOnly = IsReadOnly;
                    settings.OnCustomGetControlModes(sender, e);
                    (sender as BarItem).Enabled = !e.IsReadOnly;
                }
            }
            else if(sender is Control)
            {
                ModeSettingsEventArgs e = new ModeSettingsEventArgs();
                e.IsReadOnly = IsReadOnly;
                settings.OnCustomGetControlModes(sender, e);
                (sender as Control).Enabled = !e.IsReadOnly;
            }
        }
        protected override void SettingsCreated(object sender, ModeSettings settings)
        {
            if (sender is GridView)
            {
                GridView gv = sender as GridView;
                if (!_Views.Contains(gv))
                {
                    _Views.Add(gv);
                    gv.RowCellStyle += new RowCellStyleEventHandler(gv_RowCellStyle);
                    gv.ShowingEditor += new System.ComponentModel.CancelEventHandler(gv_ShowingEditor);
                    gv.GridControl.FocusedViewChanged += new DevExpress.XtraGrid.ViewFocusEventHandler(GridControl_FocusedViewChanged);
                    gv.FocusedRowChanged += new FocusedRowChangedEventHandler(gv_FocusedRowChanged);
                    gv.MasterRowExpanded += new CustomMasterRowEventHandler(gv_MasterRowExpanded);
                    gv.KeyDown += new KeyEventHandler(gv_KeyDown);
                    if (gv.GridControl != null && !_Grids.Contains(gv.GridControl))
                    {
                        _Grids.Add(gv.GridControl);
                    }
                }
                RefreshGridNewItemRowPos(gv);
            }
            if (sender is GridColumn)
            {
                
            }
            settings.ReadOnlyModes = DefaultReadOnlyModes;
        }
        protected override object GetRealKey(object target)
        {
            object key = target;

            if (target is BaseView)
            {
                BaseView gv = target as BaseView;
                if (gv.SourceView != null)
                    key = gv.SourceView;
            }
            if (target is GridColumn)
            {
                if ((target as GridColumn).View != null && (target as GridColumn).View.SourceView != null)
                {
                    foreach (GridColumn c in ((target as GridColumn).View.SourceView as ColumnView).Columns)
                    {
                        if (c.Name == (target as GridColumn).Name)
                        {
                            return c;
                        }
                    }
                }
            }
            return key;
        }
        private void gv_KeyDown(object sender, KeyEventArgs e)
        {
            GridView gv = sender as GridView;
            if (e.KeyCode == Keys.Delete)
            {
                object key = GetRealKey(sender);
                if (key != null)
                {
                    if (_AllSettings.ContainsKey(key))
                    {
                        ModeSettings settings = _AllSettings[key];
                        if (settings != null)
                        {
                            if (settings.AllowDeleteRecordModes != FormMode.None)
                            {
                                FormMode m = CurrentMode;
                                if (settings.ParentRowAsModeSetter.IsTrue(this.DefaultParentRowAsModeSetterForViews))
                                {
                                    if (gv.SourceRow != null && gv.SourceRow is DataRowView)
                                    {
                                        DataRow r = (gv.SourceRow as DataRowView).Row;
                                        if (r != null)
                                        {
                                            if (r.RowState == DataRowState.Added)
                                            {
                                                m = FormMode.New;
                                            }
                                        }
                                    }
                                }
                                if ((settings.AllowDeleteRecordModes & m) != FormMode.None)
                                {
                                    DataRow[] rows = gv.GetSelectadDataRows();
                                    {
                                        foreach (DataRow r in rows)
                                        {
                                            RowDeletingEventArgs ea = new RowDeletingEventArgs(r);
                                            settings.OnRowDeleting(this, ea);
                                            if (!ea.Cancel)
                                                r.Delete();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        private void gv_MasterRowExpanded(object sender, CustomMasterRowEventArgs e)
        {
            GridView parent = (sender as GridView);
            if (parent != null)
            {
                GridView gv = parent.GetDetailView(e.RowHandle, e.RelationIndex) as GridView;
                if (gv != null)
                    RefreshGridNewItemRowPos(gv);
            }
        }
        private void GridControl_FocusedViewChanged(object sender, DevExpress.XtraGrid.ViewFocusEventArgs e)
        {
            RefreshGridNewItemRowPos(e.View as GridView);
        }
        private void RefreshGridNewItemRowPos(GridView gv)
        {
            object key = GetRealKey(gv);
            if (key != null)
            {
                if (_AllSettings.ContainsKey(key))
                {
                    ModeSettings settings = _AllSettings[key];
                    if (settings != null)
                    {
                        if (settings.AllowNewRecordModes != FormMode.None)
                        {
                            NewItemRowPosition pos = NewItemRowPosition.None;
                            FormMode m = CurrentMode;
                            if (settings.ParentRowAsModeSetter.IsTrue(this.DefaultParentRowAsModeSetterForViews))
                            {
                                if (gv.SourceRow != null && gv.SourceRow is DataRowView)
                                {
                                    DataRow r = (gv.SourceRow as DataRowView).Row;
                                    if (r != null)
                                    {
                                        if (r.RowState == DataRowState.Added)
                                        {
                                            m = FormMode.New;
                                        }
                                    }
                                }
                            }
                            if ((settings.AllowNewRecordModes & m) != FormMode.None)
                            {
                                if (settings.NewRowAtTop)
                                    pos = NewItemRowPosition.Top;
                                else
                                    pos = NewItemRowPosition.Bottom;

                            }
                            gv.OptionsView.NewItemRowPosition = pos;
                            gv.Invalidate();
                        }
                    }
                }
            }
        }

        void gv_FocusedRowChanged(object sender, FocusedRowChangedEventArgs e)
        {
            RefreshGridNewItemRowPos(sender as GridView);
        }

        private ModeSettingsForColumnEventArgs getSettings(object sender, GridColumn column, int rowHandle)
        {
            ModeSettingsForColumnEventArgs ev = new ModeSettingsForColumnEventArgs(column, rowHandle);

            ModeSettings settings  = GetSettings(column);
            if (settings != null)
            {
                FormMode m = CurrentMode;
                if (settings.RowAsModeSetter.IsTrue(DefaultRowAsModeSetterForColumns))
                {
                    DataRow row = (sender as GridView).GetDataRow(rowHandle);

                    if (row == null || row.RowState == DataRowState.Added || row.RowState == DataRowState.Detached)
                        m = FormMode.New;
                }
                bool IsReq = (settings.RequiredModes & m) != FormMode.None;
                bool IsReadOnly = (settings.ReadOnlyModes & m) != FormMode.None;

                ev.IsReadOnly = IsReadOnly;
                ev.IsRequired = IsReq;
                settings.OnCustomGetGridColumnModes(sender, ev);
            }
            return ev;
        }

        void gv_ShowingEditor(object sender, System.ComponentModel.CancelEventArgs e)
        {
            GridView gv = sender as GridView;
            if (gv != null)
            {
                GridColumn col =gv.FocusedColumn;
                ModeSettingsForColumnEventArgs ev = getSettings(sender, col, gv.FocusedRowHandle);
                col.OptionsColumn.ReadOnly = ev.IsReadOnly;
            }
        }

        void gv_RowCellStyle(object sender, RowCellStyleEventArgs e)
        {
            ModeSettingsForColumnEventArgs ev = getSettings(sender, e.Column, e.RowHandle);
            if (ev.IsReadOnly)
                e.Appearance.SetReadOnlyAppearance();
            else if (ev.IsRequired)
                e.Appearance.SetRequiredAppearance();
            else
                e.Appearance.Reset();
        }

        public override bool CanExtend(object extendee)
        {
            if (extendee is BaseEdit ||
                extendee is GridColumn || 
                extendee is SimpleButton ||
                (extendee is BarItem && !( extendee is BarSubItem)) ||
                extendee is GridView)
                return true;
            return false;
        }

        public string[] GetRequiredColumns(GridView gv)
        {
            List<string> list = new List<string>();
            ModeSettings s =null;
            foreach (GridColumn c in gv.Columns)
            {
                object key = GetRealKey(c);
                if (key != null && _AllSettings.ContainsKey(key))
                {
                    s = _AllSettings[key];
                    if ((s.RequiredModes & CurrentMode) != FormMode.None)
                    {
                        list.AddIfNotExist(c.FieldName);
                    }
                }
            }
            return list.ToArray();
        }

    }
}
